import streamlit as st
import pandas as pd
import numpy as np
import os
from datetime import datetime

# 设置Pandas Styler的最大渲染元素数
pd.set_option("styler.render.max_elements", 3000000)  # 设置为300万，根据你的数据量调整

# 设置页面
st.set_page_config(page_title="ATM数据分析", layout="wide")

hide_streamlit_style = """
    <style>
    #MainMenu {visibility: hidden;}
    footer {visibility: hidden;}
    .st-emotion-cache-4z1n4l.erv3yhi2 {
        display: none;
    }
    .st-emotion-cache-scp8yw.e3g0k5y6 {
        display: none;
    }
    </style>
"""



st.markdown(hide_streamlit_style, unsafe_allow_html=True)

# 自定义标题
st.markdown("""
    <h1 style='text-align: center; color: #1f77b4; margin-bottom: 30px;'>
        ATM数据分析
    </h1>
""", unsafe_allow_html=True)


# 数据加载函数
@st.cache_data
def load_data():
    """数据加载函数 - 从CSV文件或上传文件加载数据"""
    try:
        file_path = "pages/atm.csv"
        if os.path.exists(file_path):
            df = pd.read_csv(file_path)
            return df
    except Exception as e:
        st.warning(f"CSV文件加载失败: {e}")

    uploaded_file = st.sidebar.file_uploader(
        "上传数据文件",
        type=['csv'],
        help="支持CSV格式文件"
    )

    if uploaded_file is not None:
        try:
            df = pd.read_csv(uploaded_file)
            return df
        except Exception as e:
            st.error(f"文件读取错误: {e}")
            return None
    return None


# 数据预处理函数
def preprocess_data(df):
    """数据清洗和预处理"""
    df_clean = df.copy()

    # 转换日期格式
    df_clean['交易日期'] = pd.to_datetime(df_clean['交易日期'], format='%Y%m%d', errors='coerce')

    # 确保数值列是数值类型
    numeric_cols = ['现金存款', '现金取款', 'ATM加钞']
    for col in numeric_cols:
        df_clean[col] = pd.to_numeric(df_clean[col], errors='coerce')

    # 计算衍生指标
    df_clean['净现金流'] = df_clean['现金存款'] - df_clean['现金取款']
    df_clean['现金利用率'] = (df_clean['现金取款'] / df_clean['ATM加钞']).fillna(0)

    # 添加月份和星期信息
    df_clean['月份'] = df_clean['交易日期'].dt.month
    df_clean['星期'] = df_clean['交易日期'].dt.day_name()

    # 处理可能的空值
    df_clean = df_clean.dropna(subset=numeric_cols)

    return df_clean


# 优化数据显示函数 - 限制显示行数
def display_dataframe_with_limit(df, max_rows=1000, height=400):
    """优化数据显示，限制行数避免性能问题"""
    if len(df) > max_rows:
        st.warning(f"数据量较大，仅显示前 {max_rows} 条记录（共 {len(df):,} 条）")
        display_df = df.head(max_rows)
    else:
        display_df = df

    # 使用原生DataFrame显示，避免Styler的性能问题
    st.dataframe(
        display_df,
        use_container_width=True,
        height=height
    )


# 主程序
def main():
    # 加载数据
    df_raw = load_data()

    if df_raw is None:
        st.error("无法加载数据，请上传CSV文件或确保当前目录下存在atm.csv文件")
        st.info("请使用左侧边栏的文件上传功能上传数据文件")
        return

    # 显示原始数据信息
    with st.expander("数据概览", expanded=False):
        col1, col2, col3, col4 = st.columns(4)
        with col1:
            st.metric("总记录数", f"{len(df_raw):,}")
        with col2:
            st.metric("机构数量", df_raw['所属机构'].nunique())
        with col3:
            st.metric("设备数量", df_raw['设备编号'].nunique())
        with col4:
            st.metric("数据日期范围",
                      f"{df_raw['交易日期'].iloc[0]} 至 {df_raw['交易日期'].iloc[-1]}"
                      if len(df_raw) > 0 else "无数据")

        st.write("数据预览（前1000条）:")
        display_dataframe_with_limit(df_raw, max_rows=1000, height=300)

    # 数据预处理
    df = preprocess_data(df_raw)

    # 侧边栏筛选器
    st.sidebar.header("数据筛选")

    # 日期范围筛选
    if len(df) > 0:
        min_date = df['交易日期'].min()
        max_date = df['交易日期'].max()

        date_range = st.sidebar.date_input(
            "选择日期范围",
            [min_date, max_date],
            min_value=min_date,
            max_value=max_date
        )
    else:
        date_range = [datetime.now(), datetime.now()]
        st.sidebar.warning("无有效数据")

    # 机构筛选 - 默认选择前10个机构
    st.sidebar.subheader("筛选条件")

    all_orgs = df['所属机构'].unique() if len(df) > 0 else []

    # 默认选择前10个机构，如果机构总数少于10个，则选择全部
    default_orgs = all_orgs[:min(10, len(all_orgs))] if len(all_orgs) > 0 else []

    selected_orgs = st.sidebar.multiselect(
        "选择所属机构",
        options=all_orgs,
        default=default_orgs,  # 默认选择前10个机构
        help="默认选择前10个机构，可多选或取消选择"
    )

    # 设备编号筛选 - 默认不选（显示全部设备）
    all_devices = df['设备编号'].unique() if len(df) > 0 else []
    selected_devices = st.sidebar.multiselect(
        "选择设备编号",
        options=all_devices,
        default=[],  # 默认不选择任何设备，显示全部
        help="默认显示全部设备，可选择特定设备进行分析"
    )

    # # 添加快速选择设备的功能
    # if len(all_devices) > 0:
    #     st.sidebar.subheader("快速选择")
    #
    #     # 按交易量排序的设备列表
    #     device_transaction_count = df.groupby('设备编号').size().sort_values(ascending=False)
    #     top_devices = device_transaction_count.head(10).index.tolist()
    #
    #     col1, col2, col3 = st.sidebar.columns([1, 1, 1])
    #     with col1:
    #         if st.button("TOP10设备"):
    #             selected_devices = top_devices
    #             st.rerun()
    #     with col2:
    #         if st.button("清空设备"):
    #             selected_devices = []
    #             st.rerun()
    #     with col3:
    #         if st.button("全部机构"):
    #             selected_orgs = all_orgs.tolist()
    #             st.rerun()

    # 应用筛选
    if len(df) > 0 and len(date_range) == 2:
        # 基础日期筛选
        date_filtered = df[
            (df['交易日期'] >= pd.to_datetime(date_range[0])) &
            (df['交易日期'] <= pd.to_datetime(date_range[1]))
            ]

        # 机构筛选
        if selected_orgs:
            org_filtered = date_filtered[date_filtered['所属机构'].isin(selected_orgs)]
        else:
            org_filtered = date_filtered

        # 设备筛选
        if selected_devices:
            filtered_df = org_filtered[org_filtered['设备编号'].isin(selected_devices)]
        else:
            filtered_df = org_filtered
    else:
        filtered_df = df

    # 显示筛选结果信息
    st.sidebar.header("筛选状态")
    if len(selected_orgs) == 0:
        st.sidebar.info("📋 所有所属机构")
    else:
        st.sidebar.info(f"📋 {len(selected_orgs)} 个所属机构")

    if len(selected_devices) == 0:
        st.sidebar.info("🏧 所有设备 ({})".format(len(all_devices)))
    else:
        st.sidebar.info(f"🏧 {len(selected_devices)} 个设备")

    st.sidebar.info(f"📊 筛选后记录: {len(filtered_df):,}")

    # # 显示当前筛选条件
    # if len(selected_orgs) > 0:
    #     st.sidebar.write("**当前选择的机构:**")
    #     for i, org in enumerate(selected_orgs[:5]):  # 只显示前5个，避免侧边栏过长
    #         st.sidebar.write(f"• {org}")
    #     if len(selected_orgs) > 5:
    #         st.sidebar.write(f"• ... 还有 {len(selected_orgs) - 5} 个机构")

    # 主显示区域 - 关键指标
    st.header("关键指标")

    if len(filtered_df) == 0:
        st.warning("没有符合筛选条件的数据，请调整筛选条件")
        return

    col1, col2, col3, col4 = st.columns(4)

    with col1:
        total_deposit = filtered_df['现金存款'].sum()
        avg_deposit = filtered_df['现金存款'].mean()
        st.metric("总存款", f"¥{total_deposit:,.0f}",
                  delta=f"¥{avg_deposit:,.0f} 笔均" if not pd.isna(avg_deposit) else None)

    with col2:
        total_withdrawal = filtered_df['现金取款'].sum()
        avg_withdrawal = filtered_df['现金取款'].mean()
        st.metric("总取款", f"¥{total_withdrawal:,.0f}",
                  delta=f"¥{avg_withdrawal:,.0f} 笔均" if not pd.isna(avg_withdrawal) else None)

    with col3:
        total_refill = filtered_df['ATM加钞'].sum()
        avg_refill = filtered_df['ATM加钞'].mean()
        st.metric("总加钞", f"¥{total_refill:,.0f}",
                  delta=f"¥{avg_refill:,.0f} 台均" if not pd.isna(avg_refill) else None)

    with col4:
        net_cash_flow = filtered_df['净现金流'].sum()
        st.metric("净现金流", f"¥{net_cash_flow:,.0f}")

    # 第二行指标
    col5, col6, col7, col8 = st.columns(4)

    with col5:
        utilization_rate = filtered_df['现金利用率'].mean() * 100
        st.metric("平均现金利用率", f"{utilization_rate:.1f}%")

    with col6:
        transaction_count = len(filtered_df)
        st.metric("交易笔数", f"{transaction_count:,}")

    with col7:
        unique_atms = filtered_df['设备编号'].nunique()
        st.metric("涉及设备数", f"{unique_atms}")

    with col8:
        unique_orgs = filtered_df['所属机构'].nunique()
        st.metric("涉及机构数", f"{unique_orgs}")

    # 可视化分析
    st.header("可视化分析")

    tab1, tab2, tab3, tab4, tab5 = st.tabs(["交易概览", "机构分析", "趋势分析", "设备分析", "详细数据"])

    with tab1:
        col1, col2 = st.columns(2)

        with col1:
            st.subheader("交易类型对比")
            summary_data = filtered_df[['现金存款', '现金取款', 'ATM加钞']].sum()
            st.bar_chart(summary_data)

        with col2:
            st.subheader("现金利用率分布")
            try:
                import plotly.express as px
                # 对大数据集进行采样以提高性能
                if len(filtered_df) > 10000:
                    sample_df = filtered_df.sample(n=10000, random_state=42)
                    st.info(f"数据量较大，随机采样 10,000 条记录进行可视化")
                else:
                    sample_df = filtered_df

                fig = px.histogram(sample_df, x='现金利用率',
                                   nbins=20, title="现金利用率分布")
                st.plotly_chart(fig, use_container_width=True)
            except Exception as e:
                st.info(f"启用Plotly以获得更好的可视化效果: {e}")

    with tab2:
        st.subheader("各机构交易情况")

        # 按机构汇总
        org_summary = filtered_df.groupby('所属机构').agg({
            '现金存款': 'sum',
            '现金取款': 'sum',
            'ATM加钞': 'sum',
            '净现金流': 'sum',
            '设备编号': 'count'
        }).rename(columns={'设备编号': '交易笔数'}).reset_index()

        # 显示机构排名表格 - 使用原生DataFrame避免Styler问题
        st.dataframe(
            org_summary,
            use_container_width=True,
            height=400
        )

        # 机构取款排名图表
        col1, col2 = st.columns(2)
        with col1:
            try:
                import plotly.express as px
                top_orgs = org_summary.nlargest(10, '现金取款')
                fig = px.bar(top_orgs, x='所属机构', y='现金取款',
                             title="取款金额TOP10机构")
                fig.update_layout(xaxis_tickangle=-45)
                st.plotly_chart(fig, use_container_width=True)
            except Exception as e:
                st.bar_chart(org_summary.set_index('所属机构')['现金取款'])

        with col2:
            try:
                fig = px.pie(org_summary.nlargest(8, '现金取款'),
                             values='现金取款', names='所属机构',
                             title="取款金额分布")
                st.plotly_chart(fig, use_container_width=True)
            except Exception as e:
                st.info(f"饼图需要Plotly支持: {e}")

    with tab3:
        st.subheader("时间趋势分析")

        # 按日期汇总
        daily_summary = filtered_df.groupby('交易日期').agg({
            '现金存款': 'sum',
            '现金取款': 'sum',
            'ATM加钞': 'sum',
            '净现金流': 'sum'
        }).reset_index()

        if len(daily_summary) > 0:
            st.line_chart(daily_summary.set_index('交易日期')[['现金存款', '现金取款', 'ATM加钞']])

            # 净现金流趋势
            st.subheader("净现金流趋势")
            st.area_chart(daily_summary.set_index('交易日期')['净现金流'])
        else:
            st.warning("无时间序列数据可展示")

    with tab4:
        st.subheader("设备分析")

        # 按设备汇总
        device_summary = filtered_df.groupby('设备编号').agg({
            '现金存款': 'sum',
            '现金取款': 'sum',
            'ATM加钞': 'sum',
            '交易日期': 'count',
            '所属机构': 'first'
        }).rename(columns={'交易日期': '交易次数'}).reset_index()

        # 添加排名
        device_summary['取款排名'] = device_summary['现金取款'].rank(ascending=False).astype(int)
        device_summary['存款排名'] = device_summary['现金存款'].rank(ascending=False).astype(int)

        st.dataframe(
            device_summary,
            use_container_width=True,
            height=400
        )

        # 设备性能分析
        if len(selected_devices) == 1:
            st.subheader(f"设备 {selected_devices[0]} 详细分析")
            device_data = filtered_df[filtered_df['设备编号'] == selected_devices[0]]

            col1, col2, col3 = st.columns(3)
            with col1:
                st.metric("该设备总取款", f"¥{device_data['现金取款'].sum():,.0f}")
            with col2:
                st.metric("该设备总存款", f"¥{device_data['现金存款'].sum():,.0f}")
            with col3:
                st.metric("该设备交易次数", len(device_data))

    with tab5:
        st.subheader("详细交易数据")

        # 显示详细数据表格 - 使用优化后的显示函数
        display_columns = ['交易日期', '所属机构', '设备编号',
                           '现金存款', '现金取款', 'ATM加钞', '净现金流']

        display_data = filtered_df[display_columns]
        display_dataframe_with_limit(display_data, max_rows=1000, height=400)

        # 数据下载功能
        if len(filtered_df) > 100000:
            st.warning("数据量较大，下载可能需要一些时间...")

        csv = filtered_df.to_csv(index=False, encoding='utf-8-sig')
        st.download_button(
            label=f"下载筛选数据 (CSV, {len(filtered_df):,} 条记录)",
            data=csv,
            file_name=f"ATM交易数据_{datetime.now().strftime('%Y%m%d_%H%M')}.csv",
            mime="text/csv"
        )


if __name__ == "__main__":
    main()